#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# credit: http://sheep.art.pl/Wiki%20Engine%20in%20Python%20from%20Scratch
import cgi
import socket
import locale
from http.server import HTTPServer,SimpleHTTPRequestHandler
import logging
import os
import subprocess
import tempfile
import urllib
from optparse import OptionParser
import json

from tools_pack.help_pack import get_arduino_command, set_ini_value, get_ini_value, guess_port_name, \
    usb_check_port_connect, bluetooth_check_port_connect, get_all_port
from tools_pack.history_pack import xml_history
from tools_pack.oled_drow import oled_show_text
from tools_pack.upload_infos import upload_infoto_server
from tools_pack import global_shared
from tools_pack.zip_parses import zip_operate

loger=logging.getLogger("metas")

arduino_cmd = None
arduino_cmd=get_arduino_command(arduino_cmd)

parser = OptionParser()
parser.add_option("--port", dest="port", help="Upload to serial port named PORT", metavar="PORT")
parser.add_option("--board", dest="board", help="Board definition to use", metavar="BOARD")
parser.add_option("--command", dest="cmd", help="Arduino command name", metavar="CMD")


class Handler(SimpleHTTPRequestHandler):
    def do_HEAD(self):
        """Send response headers"""
        if self.path != "/":
            return SimpleHTTPRequestHandler.do_HEAD(self)
        self.send_response(200)
        self.send_header("content-type", "text/html;charset=utf-8")
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()

    def do_GET(self):
        """Send page text"""
        if self.path=='/select_board/':
            board=get_ini_value('metas_conf', 'board')
            board_name=get_ini_value('metas_conf', 'board_name')
            board_text=board+";"+board_name
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(board_text))
            self.end_headers()
            self.wfile.write(board_text.encode("utf-8"))
        elif len(self.path.split('get_images')) == 2 and self.path.split('get_images')[0] == '/':
            _type = None
            if '?' in self.path:  # 如果带有参数
                query = urllib.parse.unquote(self.path.split('?', 1)[1])
                # name=str(bytes(params['name'][0],'GBK'),'utf-8')
                params = urllib.parse.parse_qs(query)
                _type = params.get('type', None)
            data = json.dumps(get_images(_type))
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=="/get_connect_type/":  #获取与arduino上一次的连接方式
            connect_type_list = [
                "0",  # usb 转串口
                "1",  # 蓝牙转串口
                "2"  # wifi
            ]
            get_connect_type=get_ini_value("connect","type")
            if get_connect_type not in connect_type_list:
                get_connect_type="0"
            elif get_connect_type=="2":
                get_connect_type="{};{}".format(get_connect_type,get_ini_value("connect","ip"))
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(get_connect_type))
            self.end_headers()
            self.wfile.write(get_connect_type.encode("utf-8"))

        elif "/port_connect_status/" in self.path:   #端口检测
            connect_type_list=[
                "0",#usb 转串口
                "1", #蓝牙转串口
                "2"  #wifi
            ]
            if "?" in self.path:
                query = urllib.parse.unquote(self.path.split('?', 1)[1])
                arg= urllib.parse.parse_qs(query)
                connect_type=arg.get("connect_type",["0"])[0]
            else:
                connect_type="0"
            if connect_type not in connect_type_list:
                connect_type="0"


            if connect_type=="0":

                state=usb_check_port_connect()
            elif connect_type=="1":
                state=bluetooth_check_port_connect()

            elif connect_type=='2':
                wifi_ip=get_ini_value('connect','wifi_ip')
                wifi_port=get_ini_value('connect','wifi_port')

                arduino_control_mode = global_shared.get_value('arduino_control_mode', '0')
                if arduino_control_mode=='1':
                    state=True
                else:
                    check_wifi = socket.socket()
                    check_wifi.settimeout(0.05)
                    try:
                        check_wifi.connect((wifi_ip,int(wifi_port)))
                        state=True
                    except Exception as e:
                        state=False
                    finally:
                        check_wifi.close()
            else:
                state=False
            if state==True:
                port_state="1"
            else:
                port_state="0"
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(port_state))
            self.end_headers()
            self.wfile.write(port_state.encode("utf-8"))
        elif self.path=="/agree_state/":   #获取授权状态  0未授权   1已授权  2不同意授权
            agree_state=get_ini_value("authorize","is_agree")
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(agree_state))
            self.end_headers()
            self.wfile.write(agree_state.encode("utf-8"))

        elif self.path=='/get_all_xml_history/':
            xml_obj=xml_history()
            xml_name_list=xml_obj.get_all_xml()
            data=json.dumps(xml_name_list)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))
        elif '/get_xml_history/' in self.path:
            if "?" in self.path:
                query = urllib.parse.unquote(self.path.split('?', 1)[1])
                arg= urllib.parse.parse_qs(query)
                xml_name=arg.get("xml_name",[""])[0]
            else:
                xml_name=""
            xml_obj=xml_history()
            result=xml_obj.get_xml_file(xml_name)
            data=json.dumps(result)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif '/delete_xml_history/' in self.path:
            if "?" in self.path:
                query = urllib.parse.unquote(self.path.split('?', 1)[1])
                arg = urllib.parse.parse_qs(query)
                xml_name = arg.get("xml_name", [""])[0]
            else:
                xml_name = ""
            xml_obj = xml_history()
            result = xml_obj.delete_xml_history(xml_name)
            data = json.dumps(result)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=='/get_arduino_control_mode/':
            arduino_control_mode=global_shared.get_value('arduino_control_mode','0')
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(arduino_control_mode))
            self.end_headers()
            self.wfile.write(arduino_control_mode.encode("utf-8"))

        elif self.path == '/get_bockly_ip_port/':
            ip=get_ini_value('bockly','ip')
            port=get_ini_value('bockly','port')
            data = json.dumps({'ip':ip,'port':port})
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))
        elif self.path=='/get_all_port/':
            com_list=get_all_port()
            tmp_user_use_port=global_shared.get_value('tmp_user_use_port', None)   #获取用户选择的端口
            if tmp_user_use_port!=None:
                current_port=tmp_user_use_port

            else:
                current_port=guess_port_name()

            data = json.dumps({'com_list': com_list, 'current_port': current_port})
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=='/get_wifi_address_info/':
            data={}
            wifi=['192.168.4.1:9000']
            user_use_ip=get_ini_value('connect','wifi_ip')
            user_use_port=get_ini_value('connect','wifi_port')
            if user_use_ip+':'+user_use_port not in wifi:
                wifi.append(user_use_ip+':'+user_use_port)
            data['wifi_list']=wifi
            data['current_wifi']=user_use_ip+':'+user_use_port
            data = json.dumps(data)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=='/get_example_list/':
            language = "en"  # 默认
            all_language = ['zh_cn', 'en']
            select_language = get_ini_value('metas_conf', 'language')
            if select_language != None and select_language != '' and select_language in all_language:
                language = select_language
            else:
                system_language = locale.getdefaultlocale()[0]  # 系统默认的语言 如zh_cn
                system_language = system_language.lower()  # 全部转成小写
                if system_language in all_language:
                    language = system_language
            dir_path=os.path.join(os.path.dirname(__file__),'example',language)
            zip_list=[]
            if os.path.isdir(dir_path)==True:
                for (root, dirs, files) in os.walk(dir_path):
                    for sub_file in files:
                        zip_list.append(sub_file.split('.')[0])
            data = json.dumps(zip_list)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif '/get_example_project/' in self.path:
            language = "en"  # 默认
            all_language = ['zh_cn', 'en']
            select_language = get_ini_value('metas_conf', 'language')
            if select_language != None and select_language != '' and select_language in all_language:
                language = select_language
            else:
                system_language = locale.getdefaultlocale()[0]  # 系统默认的语言 如zh_cn
                system_language = system_language.lower()  # 全部转成小写
                if system_language in all_language:
                    language = system_language

            if "?" in self.path:
                query = urllib.parse.unquote(self.path.split('?', 1)[1])
                arg = urllib.parse.parse_qs(query)
                name = arg.get("name", [""])[0]
            else:
                name = ""
            if name=='':
                file_dict={}
            else:
                file_name=name+'.mt'
                file_path = os.path.join(os.path.dirname(__file__), 'example', language,file_name)
                if os.path.isfile(file_path)==True:
                    zip_obj=zip_operate(file_path)
                    file_dict=zip_obj.file_list_info()
                else:
                    file_dict={}
            data = json.dumps(file_dict)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=='/get_first_open/':
            first_open=get_ini_value('metas_conf','first_open')

            result={'first_open':first_open}
            set_ini_value('metas_conf','first_open',b'1')
            data=json.dumps(result)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=='/get_current_language/':
            language = "en"  # 默认
            all_language = ['zh_cn','en']
            select_language = get_ini_value('metas_conf', 'language')
            if select_language != None and select_language != '' and select_language in all_language:
                language=select_language
            else:
                system_language = locale.getdefaultlocale()[0]  # 系统默认的语言 如zh_cn
                system_language = system_language.lower()  # 全部转成小写
                if system_language in all_language:
                    language=system_language
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.send_header("Content-length", len(language))
            self.end_headers()
            self.wfile.write(language.encode("utf-8"))

        elif self.path != "/":
            return SimpleHTTPRequestHandler.do_GET(self)
        else:
            language = "en"  # 默认
            all_language = ['zh_cn', 'en']
            select_language = get_ini_value('metas_conf', 'language')
            if select_language != None and select_language != '' and select_language in all_language:
                language = select_language
            else:
                system_language = locale.getdefaultlocale()[0]  # 系统默认的语言 如zh_cn
                system_language = system_language.lower()  # 全部转成小写
                if system_language in all_language:
                    language = system_language
            arduino_control_mode = global_shared.get_value('arduino_control_mode', '0')
            if language=='zh_cn':
                if arduino_control_mode=='0':
                    toolbox='simple'
                else:
                    toolbox='js_simple'
            else:
                if arduino_control_mode=='0':
                    toolbox='en_simple'
                else:
                    toolbox='en_js_simple'
            self.send_response(302)
            self.send_header("Location", "/blockly/apps/blocklyduino/index.html?mrc_language=%s&toolbox=%s" %(language,toolbox))
            self.end_headers()

    def do_POST(self):
        """Save new page text and display it"""
        if self.path=='/select_board/':  #选择板子的类型
            length = int(self.headers.get('content-length'))

            if length:
                text = self.rfile.read(length)
                # print(text.decode("utf-8-sig")),type(text.decode("utf-8-sig"))
                board_text=text.decode("utf-8")
                board_list=board_text.split(";")
                set_ini_value('metas_conf', 'board',board_list[0].encode("utf-8-sig"))
                set_ini_value('metas_conf', 'board_name',board_list[1].encode("utf-8-sig"))
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)
        elif self.path == '/upload_file/':
            length = int(self.headers.get('content-length'))
            form = cgi.FieldStorage(
                fp=self.rfile,
                headers=self.headers,
                environ={'REQUEST_METHOD':'POST'})
            data = json.dumps(upload_file(form))
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("Content-length", len(data))
            self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(data.encode("utf-8"))

        elif self.path=="/select_board_connect_type/":   #选择板子的连接方式
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                text=text.decode("utf-8")
                qtype_list=text.split(";")

                if qtype_list==0 or qtype_list[0] not in ["0","1","2"]:
                    self.send_response(400)
                # elif qtype_list[0]=="2" and qtype_list.__len__()<2:
                #     self.send_response(400)
                else:
                    # if qtype_list[0]=="2":
                    #     set_ini_value('connect', 'ip', qtype_list[1].encode("utf-8"))
                    set_ini_value('connect', 'type',qtype_list[0].encode("utf-8"))
                    self.send_response(200)
                    self.send_header('Access-Control-Allow-Origin', '*')
                    self.end_headers()
            else:
                self.send_response(400)
        elif self.path=='/oled_display/':
            length = int(self.headers.get('content-length'))
            return_data={'data':[]}
            if length:
                text = self.rfile.read(length)
                try:
                    json_text=json.loads(text)
                except Ellipsis as e:
                    loger.error(e)
                keys=list(json_text.keys())
                if 'text' in keys and 'x' in keys and 'y' in keys:
                    text=json_text.get('text','')
                    text=text.strip('"')
                    old_obj=oled_show_text()
                    hex_list=old_obj.one_row_show(text,json_text.get('x',''),json_text.get('y',''))
                    return_data['data']=hex_list

                data=json.dumps(return_data)
                self.send_response(200)
                self.send_header("Content-type", "application/json")
                self.send_header("Content-length", len(data))
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
                self.wfile.write(data.encode("utf-8"))
        elif self.path=="/oled_multiple_display/":
            length = int(self.headers.get('content-length'))
            return_data = {'data': []}
            if length:
                text = self.rfile.read(length)

                try:
                    json_text = json.loads(text)
                except Ellipsis as e:
                    loger.error(e)
                keys = list(json_text.keys())
                if 'text_list' in keys:
                    text = json_text.get('text_list', [])
                    text_list=[]
                    for key in text:
                        text_list.append(key.strip('"'))
                    old_obj = oled_show_text()
                    hex_list = old_obj.multiple_row_show(text_list)
                    return_data['data'] = hex_list

                data = json.dumps(return_data)
                self.send_response(200)
                self.send_header("Content-type", "application/json")
                self.send_header("Content-length", len(data))
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
                self.wfile.write(data.encode("utf-8"))
        elif self.path=="/post_agree_state/":  #修改用户授权状态
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                state=text
                set_ini_value("authorize","is_agree",state)
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)
        elif self.path=="/post_arduino_control_mode/":
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                state = text
                if state==b'0':
                    global_shared.set_value('arduino_control_mode','0')  #0是离线烧录模式  1是在线使用pymata控制模式
                elif state==b'1':
                    global_shared.set_value('arduino_control_mode','1')
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)
        elif self.path=='/post_select_port/':
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                text=text.decode('utf-8')
                global_shared.set_value('tmp_user_use_port',text)   #设置用户选择的端口
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)
        elif self.path=='/post_wifi_address/':   #选择wifi的地址和端口
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                text = text.decode('utf-8')
                address_list=text.split(':')
                if address_list.__len__()==2:
                    set_ini_value('connect','wifi_ip',address_list[0].encode('utf-8'))
                    set_ini_value('connect','wifi_port',address_list[1].encode('utf-8'))
                    self.send_response(200)
                    self.send_header('Access-Control-Allow-Origin', '*')
                    self.end_headers()
                else:
                    self.send_response(400)

            else:
                self.send_response(400)

        elif self.path=='/upload_online_run_xml/':   #在线模式上传用户执行积木的记录到服务器
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                text_dict = json.loads(text)
                arduino_code = text_dict.get('arduino_code', '')
                xml_code = text_dict.get('xml', '')
                block_count = text_dict.get('block_count', 0)  # 积木的数量
                user_edit = text_dict.get('user_edit', 0)  # 1是用户编辑 0非用户编辑
                if user_edit == 1 and block_count > 0:  # 判断积木的数量
                    xml_obj = xml_history()
                    xml_obj.create_xml_file(xml_data=xml_code)  # 记录用户的编辑积木历史
                    temp_upload_info = {"code_arduino": arduino_code, "code_xml": xml_code}
                    upload_obj = upload_infoto_server(post_data=temp_upload_info)
                    upload_obj.start()
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)
        elif self.path=='/post_choose_language/':
            all_language = ['zh_cn', 'en']
            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                text = text.decode('utf-8')
                if text in all_language:
                    set_ini_value('metas_conf', 'language',text.encode('utf-8'))
                self.send_response(200)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
            else:
                self.send_response(400)



        elif self.path != "/":
            return SimpleHTTPRequestHandler.do_POST(self)
        else:
            options, args = parser.parse_args()

            length = int(self.headers.get('content-length'))
            if length:
                text = self.rfile.read(length)
                loger.info("arduino code and xml: {}".format(text))
                # print "sketch to upload: " + text

                text_dict=json.loads(text)
                arduino_code=text_dict.get('arduino_code','')
                xml_code=text_dict.get('xml','')
                block_count=text_dict.get('block_count',0) #积木的数量
                user_edit=text_dict.get('user_edit',0)  #1是用户编辑 0非用户编辑
                if user_edit==1 and block_count>0: #判断积木的数量
                    xml_obj = xml_history()
                    xml_obj.create_xml_file(xml_data=xml_code)   #记录用户的编辑积木历史
                    temp_upload_info={"code_arduino":arduino_code,"code_xml":xml_code}
                    upload_obj=upload_infoto_server(post_data=temp_upload_info)
                    upload_obj.start()
                arduino_code = bytearray(arduino_code, encoding="utf-8")
                dirname = tempfile.mkdtemp()
                sketchname = os.path.join(dirname, os.path.basename(dirname)) + ".ino"
                f = open(sketchname, "wb")
                f.write(arduino_code + b"\n")
                f.close()

                # print "created sketch at %s" % (sketchname,)

                # invoke arduino to build/upload
                port=options.port or guess_port_name()


                tmp_user_use_port=global_shared.get_value('tmp_user_use_port',None)
                if tmp_user_use_port!=None:  #判断用户是否选择端口
                    port=tmp_user_use_port

                compile_args = [
                    options.cmd or get_arduino_command(arduino_cmd),
                    "--upload",
                    "--port",
                    port,
                ]

                if port == None or port=='':
                    loger.error("arduino port error, {}".format(500))
                    self.send_response(500)
                    self.send_header('Access-Control-Allow-Origin', '*')
                    self.end_headers()
                    return

                # options.board='arduino:avr:uno'
                options.board=get_ini_value('metas_conf', 'board')
                if options.board:
                    compile_args.extend([
                        "--board",
                        options.board
                    ])
                compile_args.append(sketchname)

                loger.info("Uploading with %s" % (" ".join(compile_args)))
                rc = subprocess.call(compile_args)
                loger.info(rc)
                if not rc == 0:
                    # print "arduino --upload returned " + `rc`
                    loger.error("arduino uploar error, {}".format(400))
                    self.send_response(400)
                    self.send_header('Access-Control-Allow-Origin', '*')
                    self.end_headers()
                else:
                    loger.error("arduino uploar success, {}".format(200))
                    self.send_response(200)
                    self.send_header('Access-Control-Allow-Origin', '*')
                    self.end_headers()
            else:
                loger.error("arduino uploar error, {}".format(400))
                self.send_response(400)
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()


def get_images(_type):
    """
    获取图片
    :param _type: 类型, 1:背景, 2:人物
    :return:
    """
    data = []
    if _type == 1:
        path = './blockly/apps/blocklyduino/img/background/'
    elif type == 2:
        path = './blockly/apps/blocklyduino/img/human/'
    else:
        return data
    # 读取目录文件 返回路径列表
    return data


def upload_file(data):
    """
    上传文件
    :param data: 操作数据
    :return:
    """
    filename = data.getvalue('file_name', 'no-name')
    filemd5 = data.getvalue('file_md5', '')
    uploadtype = data.getvalue('upload_type', 'background')
    if filemd5:
        filename = filemd5[8:-8] + '.' + filename.split('.').pop()
    path = ('blockly', 'apps', 'blocklyduino', 'img', uploadtype, filename)
    f = open(os.path.join('.', *path), 'wb')
    f.write(data.getvalue('uploadcore-input', ''))
    # print(data.keys())
    # print('/'.join(('',) + path))
    return {
        'status': 1,
        'url': '/'.join(('',) + path),
        'upload_type': uploadtype,
    }


def run_server(ip, port):
    server = HTTPServer((ip, port), Handler)
    server.pages = {}
    server.serve_forever()


if __name__ == '__main__':
    loger.info("Blocklyduino can now be accessed at http://127.0.0.1:8080/")
    server = HTTPServer(("127.0.0.1", 8080), Handler)
    server.pages = {}
    server.serve_forever()
